/*
 *	Copyright (c) 2009, libBasement
 *	All rights reserved.
 *	
 *	Redistribution and use in source and binary forms, with or without modification,
 *	are permitted provided that the following conditions are met:
 *	
 *	Redistributions of source code must retain the above copyright notice,
 *	this list of conditions and the following disclaimer.
 *	Redistributions in binary form must reproduce the above copyright notice,
 *	this list of conditions and the following disclaimer in the documentation
 *	and/or other materials provided with the distribution.
 *	Neither the name of the <ORGANIZATION> nor the names of its contributors may
 *	be used to endorse or promote products derived from this software without
 *	specific prior written permission.
 *	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 *	AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 *	THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 *	ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
 *	FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 *	(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *	LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 *	ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *	(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 *	SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#import <exception>

#ifndef __cplusplus
#	error RALambda requires C++.
#endif

#ifndef RALambda_h
#define RALambda_h 1

/*!
 @defined		lambda
 @abstract		Create a lambda/anonymous function.
 @param			returnType	The return type of the function
 @param			arguments	The list of arguments the lambda takes, enclosed in parantheses.
 @param			...			The contents of the lambda.
 @discussion	Lambdas generated by this macro <b>do not</b> have
				access to local variables, although this may sound
				like a major drawback, it does mean they can be safely
				passed around.<br /><br />
				<i>Typical usage:</i><br />
				<pre>
Lambda eachFunction = lambda(BOOL, (id each), {
    if([each isEqualTo:@""])
        return NO;
    return YES;
});
				</pre>
 */
#define lambda(returnType, arguments, ...) ({ \
	class { \
	public: \
		static returnType lambda arguments throw(_LambdaNextException) { \
			/* Basic introspection variables */\
			const char *__returnType__ = "" #returnType ""; (void)__returnType__; \
			const char *__arguments__ = "" #arguments ""; (void)__arguments__; \
			const char *__function__ = #returnType " " #arguments; (void)__function__; \
			__VA_ARGS__; \
		} \
	} functor; \
	functor.lambda; \
})


//Ignore
class _LambdaNextException : public std::exception
{
public:
	_LambdaNextException() : exception() {}
};

/*!
 @defined		next
 @abstract		Instruct the caller of a lambda to move onto the next bit of data.
 @discussion	This macro simply throws an exception and should not be used unless you are absolutely sure of the environment your lambda is being called in.
 */
#define next ({ throw _LambdaNextException(); })

/*!
 @defined	BeginNextTrap
 @abstract	Mark the beginning of an area of code within a loop as supporting the lambda next statement.
 */
#define BeginNextTrap try {

/*!
 @defined	BeginNextTrap
 @abstract	Mark the end of an area of code within a loop as supporting the lambda next statement.
 */
#define EndNextTrap } catch(_LambdaNextException &e) { continue; }


/*!
 @typedef	Lambda
 @abstract	The type associated with the lambda constructor.
 */
typedef void *(*Lambda)(...);

/*!
 @typedef	BoolLambda
 @abstract	The Bool type associated with the lambda constructor.
 */
typedef bool(*BoolLambda)(...);

/*!
 @typedef	VoidLambda
 @abstract	An empty lambda function type.
 */
typedef void (*VoidLambda)(void);

#endif /* RALambda_h */
